package cn.demoncat.util.pay.alipay.constant;

import org.apache.commons.lang3.StringUtils;

/**
 * 支付宝常量
 * 
 * @author 延晓磊
 *
 * @since 2019年9月24日
 */
public class AlipayConstant {
	
	/**
	 * 支付宝网关
	 */
	public static final String SERVER_URL = "https://openapi.alipay.com/gateway.do";
	/**
	 * 支付宝沙箱（模拟）网关
	 */
	public static final String SERVER_URL_DEV = "https://openapi.alipaydev.com/gateway.do";

	/**
	 * 支付宝接口
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月15日
	 */
	public enum Api {
		PAY_NATIVE("101", "扫码支付"),
		PAY_APP("102", "APP支付"),
		PAY_MWEB("103", "H5支付"),
		PAY_QUERY("110", "支付查询"), 
		PAY_CLOSE("120", "关闭支付"), 
		REFUND("130", "申请退款"), 
		REFUND_QUERY("140", "退款查询"), 
		DOWNLOAD_BILL("150", "下载对账单"),
		DOWNLOAD_FLOW("160", "下载资金流水");
		
		// 编码
		private final String code;
		// 名称
		private final String name;

		/**
		 * 根据编码获取枚举
		 * 
		 * @param code
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static Api getByCode(String code) {
			for (Api e : Api.values()) {
				if (e.getCode().equals(code)) {
					return e;
				}
			}
			return null;
		}

		Api(String code, String name) {
			this.code = code;
			this.name = name;
		}

		public String getCode() {
			return code;
		}
		public String getName() {
			return name;
		}
	}
	
	/**
	 * 支付超时时间
	 * 
	 * 限：1m～15d，m-分钟，h-小时，d-天，1c-当天，不能使用小数，默认2小时
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月17日
	 */
	public static final class PayTimeout{
		/**
		 * 30分钟
		 */
		public static final String M30 = "30m";
		/**
		 * 1小时
		 */
		public static final String H1 = "1h";
		/**
		 * 2小时（默认）
		 */
		public static final String H2 = "2h";
		/**
		 * 12小时
		 */
		public static final String H12 = "12h";
		/**
		 * 1天
		 */
		public static final String D1 = "1d";
	}
	
	/**
	 * 支付类型
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月24日
	 */
	public enum TradeType{
		// 1 线上，1支付宝，* 方式
		NATIVE("111", "FAST_INSTANT_TRADE_PAY", "扫码支付", "PC网站"),	
		APP("112", "QUICK_MSECURITY_PAY", "APP支付", "APP"),		
		MWEB("113", "QUICK_WAP_WAY", "H5支付", "手机网站");
	 
		// 编码
		private final String code;
		// 支付类型
		private final String type;
		// 支付名称
		private final String name;
		// 场景描述
		private final String description;
		
		/**
		 * 根据类型获取枚举
		 * 
		 * @param type
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static TradeType getByType(String type) {
			for (TradeType e : TradeType.values()) {
				if (e.getType().equals(type)) {
					return e;
				}
			}
			return null;
		}
		
		/**
		 * 根据编码获取枚举
		 * 
		 * @param code
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static TradeType getByCode(String code) {
			for (TradeType e : TradeType.values()) {
				if (e.getCode().equals(code)) {
					return e;
				}
			}
			return null;
		}

		TradeType(String code, String type, String name, String description) {
			this.code = code;
			this.type = type;
			this.name = name;
			this.description = description;
		}
		
		public String getCode() {
			return code;
		}
		public String getType() {
			return type;
		}
		public String getName() {
			return name;
		}
		public String getDescription() {
			return description;
		}
	}
 
	/**
	 * 账单模式
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月27日
	 */
	public static final class BillMode{
		/**
		 * 业务明细账单（支付退款对账单）：商户的支付宝交易退款的业务明细
		 */
		public static final String TRADE = "trade";
		/**
		 * 账务账单明细（资金流水账单）：商户的支付宝余额收支变动明细
		 */
		public static final String SIGNCUSTOMER = "signcustomer";
	}

	/**
	 * 账单类型/收支类型
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月15日
	 */
	public enum BillType {
		// 成功支付的订单
		PAY("1", "交易"),
		// 退款的订单
		REFUND("2", "退款");
		 
		// 编码
		private final String code;
		// 名称
		private final String name;
		
		/**
		 * 根据编码获取枚举
		 * 
		 * @param code
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static BillType getByCode(String code) {
			for (BillType e : BillType.values()) {
				if (e.getCode().equals(code)) {
					return e;
				}
			}
			return null;
		}
		
		/**
		 * 根据name获取枚举
		 * 
		 * @param name
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static BillType getByName(String name) {
			for (BillType e : BillType.values()) {
				if (e.getName().equals(name)) {
					return e;
				}
			}
			return null;
		}
		
		BillType(String code, String name) {
			this.code = code;
			this.name = name;
		}
		public String getCode() {
			return code;
		}
		public String getName() {
			return name;
		}
	}
	
	/**
	 * 收支类型（资金流水类型）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年10月15日
	 */
	public enum FlowType {
		
		INCOME("1", "收入"),
		EXPEND("2", "支出");
		 
		// 编码
		private final String code;
		// 名称
		private final String name;
		
		/**
		 * 根据编码获取枚举
		 * 
		 * @param code
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static FlowType getByCode(String code) {
			for (FlowType e : FlowType.values()) {
				if (e.getCode().equals(code)) {
					return e;
				}
			}
			return null;
		}
		
		/**
		 * 根据name获取枚举
		 * 
		 * @param name
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static FlowType getByName(String name) {
			for (FlowType e : FlowType.values()) {
				if (e.getName().equals(name)) {
					return e;
				}
			}
			return null;
		}
		
		FlowType(String code, String name) {
			this.code = code;
			this.name = name;
		}
		public String getCode() {
			return code;
		}
		public String getName() {
			return name;
		}
	}
	
	/**
	 * 商品主类型
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月27日
	 */
	public enum GoodsType{
		
		// 虚拟类商品(不支持花呗)
		VIRTUAL("0", "虚拟商品"),	
		// 实物类商品
		TANGIBLE("1", "实物商品");	
		
		// 编码
		private final String code;
		// 名称
		private final String name;
 
		/**
		 * 根据编码获取枚举
		 * 
		 * @param code
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static GoodsType getByCode(String code) {
			for (GoodsType e : GoodsType.values()) {
				if (e.getCode().equals(code)) {
					return e;
				}
			}
			return null;
		}
		
		GoodsType(String code, String name) {
			this.code = code;
			this.name = name;
		}

		public String getCode() {
			return code;
		}

		public String getName() {
			return name;
		}
	}
	
	/**
	 * 交易状态
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月27日
	 */
	public enum TradeStatus{
		
		// 等待买家付款
		WAIT_BUYER_PAY("10", "WAIT_BUYER_PAY", "交易创建"),	
		// 支付成功，可以退款
		TRADE_SUCCESS("21", "TRADE_SUCCESS", "交易成功"),	
		// 付款超时关闭、支付完成后全额退款
		TRADE_CLOSED("40", "TRADE_CLOSED", "交易关闭"),		
		// 交易成功，并且已经超过可退款期限
		TRADE_FINISHED("99", "WAIT_BUYER_PAY", "交易结束");	
		
		// 编码
		private final String code;
		// 支付宝状态
		private final String status;
		// 描述
		private final String msg;
		
		/**
		 * 根据支付宝状态获取枚举
		 * 
		 * @param status
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static TradeStatus getByStatus(String status) {
			return TradeStatus.valueOf(status);
		}
		
		/**
		 * 根据编码获取枚举
		 * 
		 * @param code
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static TradeStatus getByCode(String code) {
			for (TradeStatus e : TradeStatus.values()) {
				if (e.getCode().equals(code)) {
					return e;
				}
			}
			return null;
		}
		
		TradeStatus(String code, String status, String msg) {
			this.code = code;
			this.status = status;
			this.msg = msg;
		}

		public String getCode() {
			return code;
		}

		public String getStatus() {
			return status;
		}

		public String getMsg() {
			return msg;
		}
	}
	
	/**
	 * 退款状态
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年9月27日
	 */
	public enum RefundStatus {
		// 退款查询接口未返回
		UNKNOWN("00", "UNKNOWN", "未知"), 
		// 实际退款状态
		REFUND_PROCESSING("10", "REFUND_PROCESSING", "退款中"), 
		REFUND_SUCCESS("21", "REFUND_SUCCESS", "退款成功"), 
		REFUND_FAIL("22", "REFUND_FAIL", "退款失败");

		// 编码
		private final String code;
		// 状态
		private final String status;
		// 描述
		private final String msg;

		/**
		 * 根据状态获取枚举
		 * 
		 * @param status
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static RefundStatus getByStatus(String status) {
			if (StringUtils.isBlank(status)) {
				return UNKNOWN;
			}
			return RefundStatus.valueOf(status);
		}

		/**
		 * 根据编码获取枚举
		 * 
		 * @param code
		 * @return
		 * 
		 * @author 延晓磊
		 *
		 * @since 2019年9月27日
		 */
		public static RefundStatus getByCode(String code) {
			for (RefundStatus e : RefundStatus.values()) {
				if (e.getCode().equals(code)) {
					return e;
				}
			}
			return null;
		}

		RefundStatus(String code, String status, String msg) {
			this.code = code;
			this.status = status;
			this.msg = msg;
		}

		public String getCode() {
			return code;
		}

		public String getStatus() {
			return status;
		}

		public String getMsg() {
			return msg;
		}
	}
	
}
